package cn.wuyi.common.persistence;



import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

import cn.wuyi.common.context.ContextHolder;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

@Component(value="dataSource")
public class DynamicDataSource extends AbstractRoutingDataSource    {

    private static Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);

    private String dataSoureName;

    private String dataSourceSwitch;

    private String mycatOpen;

    private boolean switchCatalog;
    
    private Properties dataSourceProperties;
     
    private String defDatasource_Id="datasource_def0";

    private Map<Object, Object> targetDataSources;

    public  DynamicDataSource() {
        Map<Object, Object> targetDataSources = getTargetDataSources();
        setTargetDataSources(targetDataSources);
//        this.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return defDatasource_Id;
    }

    @Override
    public Connection getConnection() throws SQLException {
        Connection conn = null;


        try {
            conn = super.getConnection();
            if (isSwitchCatalog()) {
            	String tenantId = ContextHolder.getContext().getTenantId();
                   
                if (tenantId == null) {
                	 conn.setCatalog("nrcp_item");
                } else {
                    String catalog = this.getCatalog(tenantId);
                    conn.setCatalog(catalog);
                }
            }else{
            	String catalog = this.getCatalog("");
            	conn.setCatalog(catalog);
            	
            }
        } catch (Exception e) {
            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
            throw new SQLException(e);
        }

        return conn;
    }

    @Override
    public Connection getConnection(String username, String password)
            throws SQLException {
        Connection conn = null;

        try {
            conn = super.getConnection(username, password);
            if (isSwitchCatalog()) {
            	String tenantId = ContextHolder.getContext().getTenantId();
                String catalog = this.getCatalog(tenantId);
                conn.setCatalog(catalog);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return conn;
    }

    /**
     * @param tenantId
     * @方法功能说明：组装数据源标识 serviceId
     * @作者 : ce
     * @创建时间 ：2015年5月14日 上午10:44:10
     */
    private String getCatalog(String tenantId) {
        if (logger.isDebugEnabled()) {
            logger.debug("Current database catalog is " + this.dataSoureName.toUpperCase() + "_" + tenantId);
        }
        if(!isSwitchCatalog()){
        	return getDataSoureName().toUpperCase();
        }
        return getDataSoureName().toUpperCase() + "_" + tenantId;
    }

    public boolean isSwitchCatalog() {

        logger.debug("### mycat_open = {} !", getMycatOpen());

        if (!StringUtils.isEmpty(this.mycatOpen) && !this.mycatOpen.contains("$") && !mycatOpen.equals("false")) {
            logger.debug("### mycat_open started !");
            return false;
        } else {
            logger.debug("#### mycat_open NOT started!");
        }

        //默认是进行数据源的切换，此时swithCatalog=true
        if (StringUtils.isEmpty(this.dataSourceSwitch) || this.dataSourceSwitch.equals("true")) {
            this.switchCatalog = true;
        } else {//如果配置了zceo.datasource.switch=true | false,则根据实际情况配置
            this.switchCatalog =false;
        }

        logger.debug("Current property [datasourceSwitch] is " + this.dataSourceSwitch + ", [switchCatalog] is " + this.switchCatalog);

        return this.switchCatalog;
    }

    public void setSwitchCatalog(boolean switchCatalog) {
        this.switchCatalog = switchCatalog;
    }

   

    

    public void registerDataSource(ApplicationContext context) {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context
                .getAutowireCapableBeanFactory();
        targetDataSources = new LinkedHashMap<Object, Object>();
        Environment env = context.getEnvironment();
       
        String dataSourceName = env.getProperty("zceo.datasource","");
        this.setDataSoureName(dataSourceName);
        String dataSourceSwitch = env.getProperty("zceo.datasource.switch","");
        this.setDataSourceSwitch(dataSourceSwitch);
        String mycatOpen = env.getProperty("mycat.open","");
        this.setMycatOpen(mycatOpen);

        String driverClassName = env.getProperty("spring.datasource.driver-class-name","");
        String jdbcUrl = env.getProperty("spring.datasource.url","");

        String username = env.getProperty("spring.datasource.username","");

        String password = env.getProperty("spring.datasource.password","");
       
        dataSourceProperties=new Properties();
        dataSourceProperties.put("driverClassName", driverClassName);
        dataSourceProperties.put("url", jdbcUrl);
        dataSourceProperties.put("username", username);
        dataSourceProperties.put("password", password);
        
        dataSourceProperties.put("initialSize", 2);
        dataSourceProperties.put("minIdle", 2);
        dataSourceProperties.put("maxActive", 20);
        dataSourceProperties.put("maxWait", 10000);
        dataSourceProperties.put("timeBetweenEvictionRunsMillis", 60000);

        dataSourceProperties.put("minEvictableIdleTimeMillis", 600000);
        dataSourceProperties.put("validationQuery", "SELECT 1");
        dataSourceProperties.put("testWhileIdle", true);
        dataSourceProperties.put("testOnBorrow", true);
        dataSourceProperties.put("testOnReturn", true);
        dataSourceProperties.put("poolPreparedStatements", true);
					
        dataSourceProperties.put("breakAfterAcquireFailure", true);// 在请求失败以后是否中断
        dataSourceProperties.put("connectionErrorRetryAttempts", 0); //请求失败尝试次数

		dataSourceProperties.put("maxOpenPreparedStatements", "20");
        dataSourceProperties.put("filters", "stat");		
      
        String dataSourceClass=env.getProperty("spring.datasource.type","");
		BeanDefinitionBuilder builder = BeanDefinitionBuilder
                .rootBeanDefinition(dataSourceClass);
        builder.setLazyInit(false);
        builder.getBeanDefinition().setAttribute("id", defDatasource_Id);

        Iterator iter = dataSourceProperties.keySet().iterator();
        
        for (; iter.hasNext(); ) {
            String propertyName = (String) iter.next();
            Object propertyValue =  dataSourceProperties.get(propertyName);
            builder.addPropertyValue(propertyName, propertyValue);
        }

        beanFactory.registerBeanDefinition(defDatasource_Id,
                builder.getBeanDefinition());
        Object datasource = context.getBean(defDatasource_Id);
        targetDataSources.put(defDatasource_Id, datasource);
        this.setTargetDataSources(targetDataSources);
    }




    public Properties getDataSourceProperties() {
        return dataSourceProperties;
    }

    public void setDataSourceProperties(Properties dataSourceProperties) {
        this.dataSourceProperties = dataSourceProperties;
    }

    public Map<Object, Object> getTargetDataSources() {
        return targetDataSources;
    }

	public String getDataSoureName() {
		return dataSoureName;
	}

	public void setDataSoureName(String dataSoureName) {
		this.dataSoureName = dataSoureName;
	}

	public String getDataSourceSwitch() {
		return dataSourceSwitch;
	}

	public void setDataSourceSwitch(String dataSourceSwitch) {
		this.dataSourceSwitch = dataSourceSwitch;
	}

	public String getMycatOpen() {
		return mycatOpen;
	}

	public void setMycatOpen(String mycatOpen) {
		this.mycatOpen = mycatOpen;
	}
}
